package com.ynet.middleground.approve.model;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import com.ynet.middleground.approve.dao.ArCommentExtMapper;
import com.ynet.middleground.approve.dto.*;
import com.ynet.middleground.approve.entity.ArCommentExt;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ynet.core.exception.BusinessException;
import com.ynet.core.log.IfpLogger;
import com.ynet.middleground.approve.bean.ProcessInstanceReq;
import com.ynet.middleground.approve.bean.QueryRepeatStartProcessReq;
import com.ynet.middleground.approve.bean.QueryRunningProcessReq;
import com.ynet.middleground.approve.constant.VotingVariables;
import com.ynet.middleground.approve.constant.WorkflowConstants;
import com.ynet.middleground.approve.dao.ArTaskExtMapper;
import com.ynet.middleground.approve.dao.TaskCommentMapper;
import com.ynet.middleground.approve.entity.ArTaskExt;
import com.ynet.middleground.approve.utils.BeanUtil;

/**
 * @author liulx
 * @description 流程历史相关业务处理
 * @date 2019-10-22 17:44
 */
@Component
public class ProcessHistoryModel {

    @Autowired
    private HistoryService historyService;

    @Autowired
    private Mapper mapper;

    @Autowired
    private TaskCommentMapper taskCommentMapper;

    @Autowired
    private ArTaskExtMapper arTaskExtMapper;

    @Autowired
    private TaskAttrModel taskAttrModel;

    @Autowired
    private ArCommentExtMapper arCommentExtMapper;

    @Autowired
    private Mapper dozerBeanMapper;

    /**
     * 根据发起人查询用户发起的未结束的流程列表 <br />
     * 解决方案1，方案2参考 {@link com.ynet.middleground.approve.model.ProcessRuntimeModel#listProcessInstanceByStartUserId}
     * <p>
     * 是否需要添加渠道判断, 目前考虑不应该加
     * </p>
     * 
     * @param req 流程信息请求对象: {流程发起人}
     * @return 由用户发起的未结束的流程列表
     */
    public List<ProcessInstanceDTO> listUnfinishedProcessByStartUserId(QueryRunningProcessReq req) {
        String startUserId = req.getStartUserId();
        if (StringUtils.isBlank(startUserId)) {
            throw new BusinessException("流程发起人不能为空", "ECAP0100");
        }
        // 创建历史流程实例，查询对象
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
        // 设置查询发起人条件
        historicProcessInstanceQuery.startedBy(startUserId);
        // 设置只查询未完成的
        historicProcessInstanceQuery.unfinished();
        historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc();
        // 数据列表

        // add by liwq on 2020-12-14 start 调整为分页查询
        // 总数
        Long total = historicProcessInstanceQuery.count();
        // 分页需要的 startIndex
        int startIndex = (req.getPagerInfo().getPageNum() - 1) * req.getPagerInfo().getPageSize();
        List<HistoricProcessInstance> list =
            historicProcessInstanceQuery.listPage(startIndex, req.getPagerInfo().getPageSize());
        req.getPagerInfo().setTotal(total);
        // add by liwq on 2020-12-14 end

        List<ProcessInstanceDTO> resultList = BeanUtil.mapList(mapper, list, ProcessInstanceDTO.class);
        IfpLogger.info("ProcessHistoryModel.listUnfinishedProcessByStartUserId", "用户: {}，未完成流程实例列表: {}", startUserId,
            resultList.toString());
        return resultList;
    }

    /**
     * 检查用户是否启动某一个流程
     *
     * @param processReq 用户是否重复启动某一流程请求对象
     */
    public void checkRepeatStartProcess(QueryRepeatStartProcessReq processReq) {
        String startUserId = processReq.getStartUserId();
        String processDefinitionKey = processReq.getProcessDefinitionKey();
        // 查询单条记录
        /*HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
            .unfinished().startedBy(startUserId).processDefinitionKey(processDefinitionKey).singleResult();*/
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().unfinished()
            .startedBy(startUserId).processDefinitionKey(processDefinitionKey).list();
        // 添加渠道判断
        // .variableValueEquals(WorkflowConstants.CHANNEL_SIGNAL, processReq.getChannel());

        if (list != null && !list.isEmpty()) {
            throw new BusinessException("用户已发起该流程", "ECAP0203");
        }
    }

    /**
     * 根据流程实例ID查询流程任务处理记录
     *
     * @param req 流程信息请求对象: {流程实例id}
     * @return 流程任务走向记录列表
     */
    public List<HistoryTaskDTO> listHistoryTaskByProcessInstanceId(ProcessInstanceReq req) {
        // 根据流程实例id 查询流程是否有效
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(req.getProcessInstanceId()).singleResult();
        Optional.ofNullable(historicProcessInstance).orElseThrow(() -> new BusinessException("流程实例信息不存在", "ECAP0200"));
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
            .includeTaskLocalVariables().includeProcessVariables().orderByTaskCreateTime().asc();
        List<HistoricTaskInstance> list =
            historicTaskInstanceQuery.processInstanceId(req.getProcessInstanceId()).list();
        return list.stream().map(t -> {
            HistoryTaskDTO historyTaskDTO = mapper.map(t, HistoryTaskDTO.class);

            // update by liwq on 2021-03-15 start
            // ①流程任务备注信息，多返回一个"type"字段，用于区分哪些是"转办"的备注
            // List<Comment> taskComments = taskService.getTaskComments(t.getId());
            // List<CommentDTO> taskCommentList = BeanUtil.mapList(mapper, taskComments, CommentDTO.class);
            List<CommentDTO> commentsAndTransfers = taskCommentMapper.listCommentsByTaskId(t.getId());
            //2023-03-10 syf 将该任务下所有的处理意见扩展数据查询出来，并将查询列表转换为 Map 集合作为临时缓存，key 为任务处理意见 id，value 为处理意见扩展数据对象
            LambdaQueryWrapper<ArCommentExt> queryWrapperExt = new LambdaQueryWrapper<>();
            queryWrapperExt.eq(ArCommentExt::getTaskId,t.getId());
            queryWrapperExt.eq(ArCommentExt::getIsDeleted,"0");
            List<ArCommentExt> arCommentExtList = arCommentExtMapper.selectList(queryWrapperExt);
            List<CommentExtDTO> commentExtDTOList = BeanUtil.mapList(dozerBeanMapper, arCommentExtList, CommentExtDTO.class);
            Map<String,CommentExtDTO> extMaps = new HashMap<>();
            commentExtDTOList.stream().forEach(e -> {
                extMaps.put(e.getCommentId(),e);
            });
            commentsAndTransfers.stream().forEach(c -> {
                c.setTaskName(t.getName());
                c.setDeleteReason(t.getDeleteReason());
                //2023-03-10 syf 增加返回附件信息 start
                if(extMaps.get(c.getId())!=null){
                    c.setCommentExtDTO(extMaps.get(c.getId()));
                }
                //2023-03-10 syf 增加返回附件信息 end
            });
            historyTaskDTO.setTaskComments(commentsAndTransfers);
            // ②返回任务读取状态(0: 待审批 1：已读 )
            // 任务没有处理人，代表需要拾取任务，读取状态置为0
            if (StringUtils.isEmpty(t.getAssignee())) {
                historyTaskDTO.setReadState(0);
            }
            // 任务有处理人，再去任务扩展表查看是否有记录，有记录才是已读
            if (StringUtils.isNotEmpty(t.getAssignee())) {
                LambdaQueryWrapper<ArTaskExt> queryWrapper = new LambdaQueryWrapper<ArTaskExt>();
                queryWrapper.eq(ArTaskExt::getUserId, t.getAssignee());
                queryWrapper.eq(ArTaskExt::getTaskId, t.getId());
                List<ArTaskExt> arTaskExts = arTaskExtMapper.selectList(queryWrapper);
                if (arTaskExts != null && arTaskExts.size() > 0) {
                    historyTaskDTO.setReadState(1);
                } else {
                    historyTaskDTO.setReadState(0);
                }
            }

            Map<String, Object> localVariables = t.getTaskLocalVariables();
            if (localVariables != null && localVariables.size() > 0) {
                // 操作结果
                if (localVariables.get(WorkflowConstants.USER_TASK_APPROVE_RESULT) != null) {
                    historyTaskDTO.setApproveResult(
                        String.valueOf(localVariables.get(WorkflowConstants.USER_TASK_APPROVE_RESULT)));
                }
                String votingNumber = (String)localVariables.get(VotingVariables.VOTING_FLAG);
                if (StringUtils.isNotBlank(votingNumber)) {
                    // 会签号
                    historyTaskDTO.setCounterSignNumber(votingNumber);
                    historyTaskDTO.setCountersign(true);
                } else {
                    historyTaskDTO.setCountersign(false);
                }
            }

            Map<String, Object> processVariables = t.getProcessVariables();
            if (processVariables != null && processVariables.size() > 0) {
                // 发起人ID
                historyTaskDTO.setStartUserId((String)processVariables.get(WorkflowConstants.START_USER_ID));
                // 发起渠道
                historyTaskDTO.setStartChannelSignal((String)processVariables.get(WorkflowConstants.CHANNEL_SIGNAL));
                // 发起时间
                historyTaskDTO
                    .setProcessStartTime(String.valueOf(processVariables.get(WorkflowConstants.FLOW_START_TIME)));
            }
            // update by liwq on 2021-03-15 end

            // 封装业务动作参数 update by liulx on 2021-03-18
            setBusinessOperateData(historyTaskDTO);
            return historyTaskDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 封装业务动作参数集合 <br>
     * {@link com.ynet.middleground.approve.model.ProcessTaskModel#setBusinessOperateData}
     * 
     * @param taskDTO 返回的任务信息传输对象
     */
    protected void setBusinessOperateData(HistoryTaskDTO taskDTO) {
        Map<String, Object> taskLocalVariables = taskDTO.getTaskLocalVariables();
        if (taskLocalVariables != null) {
            Object businessOperation = taskLocalVariables.get(WorkflowConstants.FLOW_BUSINESS_OPERATE_DATA);
            Map<String, Object> businessOperationMap =
                (businessOperation != null) ? (Map<String, Object>)businessOperation : new HashMap<>(16);

            // 查询现所有可配置的动作参数，并判断任务变量池当中是否已存在该参数，若有则放入业务动作集合中
            List<TaskAttrDTO> listTaskAttr = taskAttrModel.listTaskAttr();
            if (CollectionUtils.isNotEmpty(listTaskAttr)) {
                for (TaskAttrDTO t : listTaskAttr) {
                    if (taskLocalVariables.containsKey(t.getCode())) {
                        businessOperationMap.put(t.getCode(), taskLocalVariables.get(t.getCode()));
                    }
                }
            }
            taskDTO.setBusinessOperateVariables(businessOperationMap);
        }
    }

}
